//
//  LBLomoFilter.mm
//  OpenGLGame
//
//  Created by Nguyen Cong Huy on 12/8/12.
//  Copyright (c) 2012 UIT. All rights reserved.
//

#include <iostream>
#include "LBLomoFilter.h"

char lomoFragStr[] = ""
"precision highp float;"

"varying highp vec2 vtexCoor;"
"varying highp vec2 vtexCoor2;"
"varying highp vec2 vtexCoor3;"

"uniform sampler2D texture;"
"uniform sampler2D texture3;"
"uniform sampler2D texture2; "


// soft light function
"vec4 softLight(vec4 base, vec4 blend, float opacity){"
"   vec4 white = vec4(1.0, 1.0, 1.0, 1.0);"
"   vec4 lumCoeff = vec4(0.2125, 0.7154, 0.0721, 1.0);"
"   vec4 result;"

"   float luminance = dot(base, lumCoeff);"
"   if (luminance < 0.45)"
"       result = 2.0 * blend * base;"
"   else if (luminance > 0.55)"
"       result = white - 2.0 * (white - blend) * (white - base);"
"   else"
"   {"
"       vec4 result1 = 2.0 * blend * base;"
"       vec4 result2 = white - 2.0 * (white - blend) * (white - base);"
"       result = mix(result1, result2, (luminance - 0.45) * 10.0);"
"   }"
"    result = mix(base, result, opacity);"
"   return result;"
"}"
// END soft light function

// linear burn function
"vec4 linearBurn(vec4 base, vec4 blend, float opacity){"
"   vec4 white = vec4(1.0, 1.0, 1.0, 1.0);"
"   vec4 result = base + blend - white; "
"   result = mix(base, result, opacity);"
"   return result;"
"}"
// END linear burn function

// overlay function
"vec4 overlay(vec4 base, vec4 blend, float opacity){"
"   vec4 white = vec4(1.0, 1.0, 1.0, 1.0);"
"   vec4 lumCoeff = vec4(0.2125, 0.7154, 0.0721, 1.0);"
"   float luminance = dot(base, lumCoeff);"
"   vec4 result;"
"   if (luminance < 0.45)"
"       result = 2.0 * blend * base;"
"   else if (luminance > 0.55)"
"       result = white - 2.0 * (white - blend) * (white - base);"
"   else"
"   {"
"       vec4 result1 = 2.0 * blend * base;"
"       vec4 result2 = white - 2.0 * (white - blend) * (white - base);"
"       result = mix(result1, result2, (luminance - 0.45) * 10.0);"
"   }"
"   result = mix(base, result, opacity);"
"   return result;"
"}"
// END overlay function

// function need for "blend saturation function"
"vec3 RGBToHSL(vec3 color)"
"{"
"    vec3 hsl;"
    
"    float fmin = min(min(color.r, color.g), color.b);   "
"    float fmax = max(max(color.r, color.g), color.b); "
"    float delta = fmax - fmin;             "
    
"    hsl.z = (fmax + fmin) / 2.0;    "
"    if (delta == 0.0)"
"    {"
"        hsl.x = 0.0;"
"        hsl.y = 0.0;"
"    }"
"    else{"
"        if (hsl.z < 0.5)"
"            hsl.y = delta / (fmax + fmin);"
"        else"
"            hsl.y = delta / (2.0 - fmax - fmin);"
        
"        float deltaR = (((fmax - color.r) / 6.0) + (delta / 2.0)) / delta;"
"        float deltaG = (((fmax - color.g) / 6.0) + (delta / 2.0)) / delta;"
"        float deltaB = (((fmax - color.b) / 6.0) + (delta / 2.0)) / delta;"
        
"        if (color.r == fmax )"
"        hsl.x = deltaB - deltaG;"
"        else if (color.g == fmax)"
"            hsl.x = (1.0 / 3.0) + deltaR - deltaB;"
"        else if (color.b == fmax)"
"            hsl.x = (2.0 / 3.0) + deltaG - deltaR;        "
"        if (hsl.x < 0.0)"
"            hsl.x += 1.0;"
"        else if (hsl.x > 1.0)"
"            hsl.x -= 1.0;"
"    }"
    
"    return hsl;"
"}"

"float HueToRGB(float f1, float f2, float hue)"
"{"
"	if (hue < 0.0)"
"		hue += 1.0;"
"	else if (hue > 1.0)"
"		hue -= 1.0;"
"	float res;"
"	if ((6.0 * hue) < 1.0)"
"		res = f1 + (f2 - f1) * 6.0 * hue;"
"	else if ((2.0 * hue) < 1.0)"
"		res = f2;"
"	else if ((3.0 * hue) < 2.0)"
"		res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0;"
"	else"
"		res = f1;"
"	return res;"
"}"

"vec3 HSLToRGB(vec3 hsl)"
"{"
"    vec3 rgb;"
    
"    if (hsl.y == 0.0)"
"        rgb = vec3(hsl.z);"
"    else"
"    {"
"        float f2;"
        
"        if (hsl.z < 0.5)"
"            f2 = hsl.z * (1.0 + hsl.y);"
"        else"
"            f2 = (hsl.z + hsl.y) - (hsl.y * hsl.z);"
        
"        float f1 = 2.0 * hsl.z - f2;"
        
"        rgb.r = HueToRGB(f1, f2, hsl.x + (1.0/3.0));"
"        rgb.g = HueToRGB(f1, f2, hsl.x);"
"        rgb.b= HueToRGB(f1, f2, hsl.x - (1.0/3.0));"
"    }"
    
"    return rgb;"
"}"
// END function need for "blend saturation function"

// blend saturation function, require RGBToHSL() and HSLToRGB() function
"vec4 blendSaturation(vec4 base, vec4 blend, float opacity)"
"{"
"    vec3 baseHSL = RGBToHSL(base.rgb);"
"    vec4 result = vec4(HSLToRGB(vec3(baseHSL.r, RGBToHSL(blend.rgb).g, baseHSL.b)), base.a);"
"   return mix(base, result, opacity);"
"}"
// END blend saturation

"const vec4 blueColor = vec4(0.026, 0.667, 1.0, 1.0);"
"const vec4 yellowColor = vec4(1.0, 0.804, 0.345, 1.0);"
"const vec4 yellowColor2 = vec4(1.0, 0.706, 0.0, 1.0);"

"void main()"
"{"
"    lowp vec4 textureColor = texture2D(texture, vtexCoor);"
"    lowp vec4 texture2Color = texture2D(texture2, vtexCoor2);"
"    lowp vec4 texture3Color = texture2D(texture3, vtexCoor3);"
"    vec4 result = textureColor;"
"    result = softLight(result, blueColor, 0.25);"  //0.25
"    result = linearBurn(result, yellowColor, 0.25);"    //0.25
"    result = softLight(result, texture2Color, 0.25);"   //0.25
"    result = overlay(result, yellowColor2, 0.2);"         //0.2
"    result = blendSaturation(result, texture3Color, 0.25);" //0.25
"    gl_FragColor = texture3Color;"
"}";


LBLomoFilter::LBLomoFilter(){
    init(0, lomoFragStr);
}

void LBLomoFilter::setBlendTexture(LBTexture * blendTexture){
    setTexture2(blendTexture);
}

void LBLomoFilter::setSaturationBlendTexture(LBTexture * blendTexture){
    setTexture3(blendTexture);
}